package com.lightboat.system.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import com.lightboat.common.config.properties.OpenApiCredentialProperties;
import com.lightboat.common.core.domain.bo.*;
import com.lightboat.common.core.text.Convert;
import com.lightboat.common.enums.*;
import com.lightboat.common.exception.ServiceException;
import com.lightboat.common.utils.DateUtils;
import com.lightboat.common.utils.spring.SpringUtils;
import com.lightboat.system.domain.*;
import com.lightboat.system.mapper.CrmLogisticsTrackMapper;
import com.lightboat.system.mapper.CrmOrderMapper;
import com.lightboat.system.service.ICrmLogisticsAddressService;
import com.lightboat.system.service.ICrmLogisticsRecordService;
import com.lightboat.system.service.IJdLogisticsService;
import com.lop.open.api.sdk.DefaultDomainApiClient;
import com.lop.open.api.sdk.LopException;
import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCreateOrderV1.*;
import com.lop.open.api.sdk.domain.ECAP.CommonModifyCancelOrderApi.commonCancelOrderV1.CommonModifyCancelOrderResponse;
import com.lop.open.api.sdk.domain.ECAP.CommonModifyCancelOrderApi.commonCancelOrderV1.CommonOrderCancelRequest;
import com.lop.open.api.sdk.domain.ECAP.CommonSubscribeTraceApi.commonSubscribeTraceV1.CommonSubscribeResponse;
import com.lop.open.api.sdk.domain.ECAP.CommonSubscribeTraceApi.commonSubscribeTraceV1.CommonSubscribeTraceRequest;
import com.lop.open.api.sdk.domain.jdcloudprint.RenderService.render4Outer.*;
import com.lop.open.api.sdk.domain.jdcloudprint.TemplateService.getTemplates.QueryTemplatesDto;
import com.lop.open.api.sdk.domain.jdcloudprint.TemplateService.getTemplates.TemplateListResultDto;
import com.lop.open.api.sdk.domain.jdcloudprint.TemplateService.getTemplates.TemplatesDto;
import com.lop.open.api.sdk.plugin.LopPlugin;
import com.lop.open.api.sdk.plugin.factory.OAuth2PluginFactory;
import com.lop.open.api.sdk.request.ECAP.EcapV1OrdersCancelLopRequest;
import com.lop.open.api.sdk.request.ECAP.EcapV1OrdersCreateLopRequest;
import com.lop.open.api.sdk.request.ECAP.EcapV1OrdersTraceSubscribeLopRequest;
import com.lop.open.api.sdk.request.jdcloudprint.CloudPrintGetTemplatesLopRequest;
import com.lop.open.api.sdk.request.jdcloudprint.CloudPrintRenderLopRequest;
import com.lop.open.api.sdk.response.ECAP.EcapV1OrdersCancelLopResponse;
import com.lop.open.api.sdk.response.ECAP.EcapV1OrdersCreateLopResponse;
import com.lop.open.api.sdk.response.ECAP.EcapV1OrdersTraceSubscribeLopResponse;
import com.lop.open.api.sdk.response.jdcloudprint.CloudPrintGetTemplatesLopResponse;
import com.lop.open.api.sdk.response.jdcloudprint.CloudPrintRenderLopResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
@Slf4j
public class JdLogisticsServiceImpl implements IJdLogisticsService {

    private final ICrmLogisticsRecordService crmLogisticsRecordService;
    private final OpenApiCredentialProperties openApiCredentialProperties;

    private final DefaultDomainApiClient client = new DefaultDomainApiClient("https://api.jdl.com",500,15000);
    // private final DefaultDomainApiClient client = new DefaultDomainApiClient("https://test-api.jdl.com",500,15000);
    private final CrmOrderMapper crmOrderMapper;
    private final CrmLogisticsTrackMapper crmLogisticsTrackMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogisticsOrderBo orderCreate(CrmOrder crmOrder, CommonCargoInfoBo cargoInfoBo){
        // 示例为调用京东快递下单前置校验接口
        try {
            Credential credential1 = openApiCredentialProperties.getJdLogistics().get(0);

            ICrmLogisticsAddressService addressService = SpringUtils.getBean(ICrmLogisticsAddressService.class);
            CrmLogisticsAddress addressByWeight = addressService.getLogisticsAddressByWeight(ExpressCompanyEnum.JINGDONGKUAIYUN.getCode());
            // 入参对象（请记得更换为自己要使用的接口入参对象）
            EcapV1OrdersCreateLopRequest request = new EcapV1OrdersCreateLopRequest();

            // 设置入参（请记得更换为自己要使用的接口入参）
            Contact senderContact  = new Contact();
            senderContact.setFullAddress(addressByWeight.getFullAddress());
            senderContact.setName(addressByWeight.getName());
            senderContact.setMobile(addressByWeight.getPhoneNumber());
            Contact receiverContact = new Contact();
            receiverContact.setName(crmOrder.getReceiverName());
            receiverContact.setMobile(crmOrder.getReceiverPhone());
            receiverContact.setFullAddress(crmOrder.getReceiverAddress());
            CommonCreateOrderRequest requestDTO = new CommonCreateOrderRequest();
            requestDTO.setOrderOrigin(1);
            requestDTO.setCustomerCode(credential1.getCustomerCode());
            CommonProductInfo productInfo = new CommonProductInfo();
            // 电商标快 ed-m-0059
            productInfo.setProductCode("ed-m-0059"); // ed-m-0001


            // 增值服务
            if (crmOrder.getCodAmount() != null && crmOrder.getCodAmount().compareTo(BigDecimal.ZERO) > 0){
                List<CommonProductInfo> commonProductInfos = new ArrayList<>();

                /**
                 * 代收货款-快递
                 * "addedProducts": [
                 *             {
                 *                 "productCode": "ed-a-0009",
                 *                 "productAttrs": {
                 *                     "shouldPayMoney":"199.99",
                 *                     "codRefundCycle":"0"
                 *                 }
                 *             }
                 * ]
                 */
                CommonProductInfo commonProductInfo = new CommonProductInfo();
                commonProductInfo.setProductCode("ed-a-0009");
                commonProductInfo.setProductAttrs(new HashMap<>(){
                    {
                        // "shouldPayMoney":"199.99"
                        put("shouldPayMoney", crmOrder.getCodAmount().toPlainString());
                        put("codRefundCycle", "3");
                    }
                });
                commonProductInfos.add(commonProductInfo);
                // 增值服务产品信息，可根据实际填写多个, 增值产品说明详细查看https://cloud.jdl.com/#/open-business-document/access-guide/267/54155
                productInfo.setAddedProducts(commonProductInfos);
            }


            requestDTO.setProductsReq(productInfo);
            requestDTO.setReceiverContact(receiverContact);
            requestDTO.setSenderContact(senderContact);

            /**
             * 付款方式 1-寄付 2-到付 3-月结 5-多方收费，orderOrigin= 0或5时，枚举值：1-寄付；2-到付；orderOrigin= 1 或4时，枚举值：1-寄付；2-到付；3-月结；orderOrigin为2时，枚举值：5-多方收费，多方收费指下单费用由多个模块或主体来支付，逆向取件时运费、包装费以及保险费用可能由商家以及C消费者分别
             */
            requestDTO.setSettleType(3);
            // 商家订单ID
            requestDTO.setOrderId(crmOrder.getOrderNo());
            requestDTO.setRemark(crmOrder.getRemark());

            List<CommonGoodsInfo> commonGoodsInfos = new ArrayList<>();

            if (ObjUtil.isNotEmpty(crmOrder.getChildrens()) && ObjUtil.isNotEmpty(crmOrder.getChildrens())) {
                List<CommonGoodsInfo> goodsInfos = new ArrayList<>();
                crmOrder.getChildrens().forEach(item -> {
                    List<CommonGoodsInfo> ored = Opt.ofNullable(item.getProductCollection()).map(m -> {
                        return m.stream().map(mm -> {
                            CommonGoodsInfo commonGoodsInfo = new CommonGoodsInfo();
                            commonGoodsInfo.setName(StrUtil.subPre(mm.getProductName(), 200));
                            commonGoodsInfo.setCode(mm.getProductId().toString());
                            commonGoodsInfo.setQuantity(mm.getNum());
                            commonGoodsInfo.setAmount(mm.getProductPrice().subtract(new BigDecimal(mm.getNum())));
                            commonGoodsInfo.setCurrencyCode("CNY");
                            return commonGoodsInfo;
                        }).toList();
                    }).orElse(new ArrayList<>());
                    goodsInfos.addAll(ored);
                });
                commonGoodsInfos.addAll(goodsInfos);
            } else {
                commonGoodsInfos = Opt.ofNullable(crmOrder.getProductCollection()).map(m -> {
                    return m.stream().map(mm -> {
                        CommonGoodsInfo commonGoodsInfo = new CommonGoodsInfo();
                        commonGoodsInfo.setName(StrUtil.subPre(mm.getProductName(), 200));
                        commonGoodsInfo.setCode(mm.getProductId().toString());
                        commonGoodsInfo.setQuantity(mm.getNum());
                        commonGoodsInfo.setAmount(mm.getProductPrice().subtract(new BigDecimal(mm.getNum())));
                        commonGoodsInfo.setCurrencyCode("CNY");
                        return commonGoodsInfo;
                    }).toList();
                }).orElseGet(() -> {
                    List<CommonGoodsInfo> goodsInfos = new ArrayList<>();
                    CommonGoodsInfo commonGoodsInfo = new CommonGoodsInfo();
                    commonGoodsInfo.setName(StrUtil.subPre(crmOrder.getProductName(), 200));
                    commonGoodsInfo.setCode(crmOrder.getOrderNo());
                    commonGoodsInfo.setQuantity(1);
                    commonGoodsInfo.setAmount(crmOrder.getProductPrice());
                    commonGoodsInfo.setCurrencyCode("CNY");
                    goodsInfos.add(commonGoodsInfo);
                    return goodsInfos;
                });
            }

            HashMap<String,String> extendProps = Maps.newHashMap();
            extendProps.put("printType", "1");
            extendProps.put("autoSubscribe", "1");
            requestDTO.setExtendProps(extendProps);

            requestDTO.setGoods(commonGoodsInfos);

            List<CommonCargoInfo> commonCargoInfos = new ArrayList<>();
            CommonCargoInfo commonCargoInfo = new CommonCargoInfo();
            commonCargoInfo.setName(cargoInfoBo.getName());
            commonCargoInfo.setQuantity(cargoInfoBo.getQuantity());
            commonCargoInfo.setWeight(cargoInfoBo.getWeight());
            commonCargoInfo.setVolume(cargoInfoBo.getVolume());
            commonCargoInfo.setLength(cargoInfoBo.getLength());
            commonCargoInfo.setWidth(cargoInfoBo.getWidth());
            commonCargoInfo.setHight(cargoInfoBo.getHight());
            commonCargoInfo.setRemark(cargoInfoBo.getRemark());
            commonCargoInfo.setCargoCode(cargoInfoBo.getCargoCode());
            commonCargoInfos.add(commonCargoInfo);
            requestDTO.setCargoes(commonCargoInfos);
            requestDTO.setRemark(cargoInfoBo.getRemark());

            request.setRequest(requestDTO);
            request.setUseJosAuth(false);

            // 设置插件，必须的操作，不同类型的应用入参不同，请看入参注释，公共参数按顺序分别为AppKey、AppSecret、AccessToken
            // 使用开放平台ISV/自研商家应用调用接口
            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(credential1.getAppKey(), credential1.getSecretKey(), credential1.getAccessToken());
            request.addLopPlugin(lopPlugin);

            EcapV1OrdersCreateLopResponse response = client.execute(request);
            log.info("物流订单创建结果：{}", JSON.toJSONString(response));
            if (response.getResult().getCode() != 0){
                log.warn("物流订单创建结果：{}", JSON.toJSONString(response));
                throw new ServiceException(response.getResult().getMsg(), Convert.toInt(response.getResult().getCode()));
            }

            CommonCreateOrderResponse orderResponse = response.getResult().getData();


            crmOrder.setLogisticsNo(orderResponse.getWaybillCode());
            crmOrder.setLogisticsPlatform(addressByWeight.getLogisticsName());
            crmOrder.setLogisticsStatus("3");
            crmOrder.setLogisticsProgress("待揽收");

            CrmLogisticsRecord crmLogisticsRecord = new CrmLogisticsRecord();
            crmLogisticsRecord.setOrderId(crmOrder.getOrderId());
            crmLogisticsRecord.setExternalOrderId(crmOrder.getExternalOrderId());
            crmLogisticsRecord.setReceiverName(crmOrder.getReceiverName());
            crmLogisticsRecord.setReceiverAddress(crmOrder.getReceiverAddress());
            crmLogisticsRecord.setReceiverPhone(crmOrder.getReceiverPhone());
            crmLogisticsRecord.setLogisticsNo(crmOrder.getLogisticsNo());
            crmLogisticsRecord.setLogisticsStatus(crmOrder.getLogisticsStatus());
            crmLogisticsRecord.setLogisticsPrice(orderResponse.getFreightPre());
            crmLogisticsRecord.setLogisticsOrder(orderResponse.getOrderCode());
            crmLogisticsRecord.setLogisticsProductCode(productInfo.getProductCode());
            crmLogisticsRecordService.save(crmLogisticsRecord);

            LogisticsOrderBo orderBo = new LogisticsOrderBo();
            orderBo.setLogisticsStatus(crmOrder.getLogisticsStatus());
            orderBo.setLogisticsCode(orderResponse.getOrderCode());
            orderBo.setLogisticsNo(orderResponse.getWaybillCode());
            orderBo.setFreightPre(orderResponse.getFreightPre());
            orderBo.setPickupPromiseTime(Opt.ofNullable(orderResponse.getPickupPromiseTime()).map(m->DateUtils.date(m).toJdkDate()).orElse(null));
            orderBo.setDeliveryPromiseTime(Opt.ofNullable(orderResponse.getDeliveryPromiseTime()).map(m->DateUtils.date(m).toJdkDate()).orElse(null));
            orderBo.setExtra(JSONObject.from(orderResponse));
            orderBo.setLogisticsPlatform(addressByWeight.getLogisticsName());
            orderBo.setLogisticsPlatformCode(addressByWeight.getLogisticsNo());
            orderBo.setSysLogisticsOrderId(orderResponse.getExtendFields().getOrDefault("orderId", crmOrder.getOrderNo()));
            orderBo.setSysOrderId(crmOrder.getOrderId());
            orderBo.setSysExternalOrderId(crmOrder.getExternalOrderId());
            return orderBo;
        } catch (Exception e) {
            e.fillInStackTrace();
            log.error("物流订单发货失败：{}", e.getMessage());
            throw new ServiceException(e);
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public LogisticsOrderBo orderCancel(CrmOrder crmOrder) {
        // 示例为调用京东快递下单前置校验接口
        try {
            Credential credential1 = openApiCredentialProperties.getJdLogistics().get(0);

            // 入参对象（请记得更换为自己要使用的接口入参对象）
            EcapV1OrdersCancelLopRequest request = new EcapV1OrdersCancelLopRequest();

            // 设置入参（请记得更换为自己要使用的接口入参）
            CommonOrderCancelRequest requestDTO = new CommonOrderCancelRequest();
            requestDTO.setOrderOrigin(1);
            requestDTO.setCustomerCode(credential1.getCustomerCode());
            requestDTO.setCancelReason("用户取消");
            requestDTO.setCancelReasonCode("1");
            // requestDTO.setWaybillCode("JDVE15365923319");
            // requestDTO.setOrderCode("");
            requestDTO.setCustomerOrderId(crmOrder.getOrderNo());
            requestDTO.setSubscribeIntercept("1");
            request.setRequest(requestDTO);

            // 设置插件，必须的操作，不同类型的应用入参不同，请看入参注释，公共参数按顺序分别为AppKey、AppSecret、AccessToken
            // 使用开放平台ISV/自研商家应用调用接口
            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(credential1.getAppKey(), credential1.getSecretKey(), credential1.getAccessToken());
            request.addLopPlugin(lopPlugin);


            // 取消结果；枚举值：0 - 取消成功；1 - 拦截成功； 2 - 取消失败；3 - 拦截失败，4-拦截中，调用成功一定返回
            EcapV1OrdersCancelLopResponse response = client.execute(request);
            CommonModifyCancelOrderResponse orderResponse = response.getResult().getData();
            log.info("物流订单取消结果：{}", JSON.toJSONString(orderResponse));

            HashMap<Integer, Integer> statusRes = new HashMap<>();
            statusRes.put(0, 4);
            statusRes.put(1, 6);
            statusRes.put(4, 5);

            // 取消结果；枚举值：0 - 取消成功；1 - 拦截成功； 2 - 取消失败；3 - 拦截失败，4-拦截中，调用成功一定返回
            // 物流状态（0 待发货 1已签收 2拒绝签收 3已发货,4取消，5拦截中，6拦截成功）
            if (Arrays.asList(2, 3).contains(orderResponse.getResultType())) {
                throw new ServiceException("取消失败");
            }

            CrmLogisticsRecord crmLogisticsRecord = new CrmLogisticsRecord();
            crmLogisticsRecord.setLogisticsStatus(statusRes.get(orderResponse.getResultType()) + "");
            if (Arrays.asList(0,1).contains(orderResponse.getResultType())) {
                crmLogisticsRecordService.update(crmLogisticsRecord,
                        Wrappers.<CrmLogisticsRecord>lambdaQuery()
                                .eq(CrmLogisticsRecord::getOrderId, crmOrder.getOrderId())
                                .eq(CrmLogisticsRecord::getLogisticsNo, crmOrder.getLogisticsNo())
                );
                crmOrder.setLogisticsStatus(crmLogisticsRecord.getLogisticsStatus());
            }

            LogisticsOrderBo orderBo = new LogisticsOrderBo();
            orderBo.setLogisticsStatus(crmOrder.getLogisticsStatus());
            orderBo.setLogisticsCode(orderResponse.getOrderCode());
            orderBo.setLogisticsNo(orderResponse.getWaybillCode());
            orderBo.setExtra(JSONObject.from(orderResponse));
            orderBo.setLogisticsPlatform(crmOrder.getLogisticsPlatform());
            orderBo.setSysLogisticsOrderId(crmOrder.getOrderNo());
            orderBo.setSysOrderId(crmOrder.getOrderId());
            orderBo.setSysExternalOrderId(crmOrder.getExternalOrderId());
            orderBo.setResultType(orderResponse.getResultType());
            return orderBo;
        }catch (Exception e) {
            e.fillInStackTrace();
        }
        return null;
    }


    /**
     * 获取订单面单模板
     * @throws IOException
     */
    @Override
    public Map<String, Object> getOrderPrintTemplates() {
        // 示例为调用京东快递下单前置校验接口
        try {
            Credential credential1 = openApiCredentialProperties.getJdLogistics().get(0);
            // 入参对象（请记得更换为自己要使用的接口入参对象）
            CloudPrintGetTemplatesLopRequest request = new CloudPrintGetTemplatesLopRequest();
            QueryTemplatesDto requestDTO = new QueryTemplatesDto();

            request.setRequest(requestDTO);
            request.setUseJosAuth(false);

            // 设置插件，必须的操作，不同类型的应用入参不同，请看入参注释，公共参数按顺序分别为AppKey、AppSecret、AccessToken
            // 使用开放平台ISV/自研商家应用调用接口
            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(credential1.getAppKey(), credential1.getSecretKey(), credential1.getAccessToken());
            request.addLopPlugin(lopPlugin);

            CloudPrintGetTemplatesLopResponse response = client.execute(request);
            TemplateListResultDto result = response.getResult();
            log.info(JSON.toJSONString(result));

            TemplatesDto templates = result.getData();

            Map<String, Object> newed = Maps.newHashMap();
            newed.put("logisticsPlatformCode", ExpressCompanyEnum.JINGDONGKUAIYUN);
            newed.put("templates", templates);
            return newed;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return Maps.newHashMap();
    }

    /**
     * 订单面单打印
     * @throws IOException
     */
    @Override
    public List<String> orderPrint(LogisticsPrintBo logisticsPrint){
        // 示例为调用京东快递下单前置校验接口
        try {
            Credential credential1 = openApiCredentialProperties.getJdLogistics().get(0);
            // 入参对象（请记得更换为自己要使用的接口入参对象）
            CloudPrintRenderLopRequest request = new CloudPrintRenderLopRequest();
            QueryRenderDTO requestDTO = new QueryRenderDTO();
            requestDTO.setCustomerCode(credential1.getCustomerCode());
            requestDTO.setTemplateCode(logisticsPrint.getTemplateCode());
            requestDTO.setOperator(logisticsPrint.getOperator());
            requestDTO.setTaskId(DateUtils.date().getTime() + "");

            List<PrintDataDTO> printDataDTOS = logisticsPrint.getPrintDatas().stream().map(printData -> {
                PrintDataDTO dataDTO = new PrintDataDTO();
                dataDTO.setOrderNumber(DateUtils.date().getTime() + "");
                dataDTO.setCarrierCode(printData.getCarrierCode());
                dataDTO.setBillCodeType(printData.getBillCodeType());
                dataDTO.setBillCodeValue(printData.getBillCodeValue());
                dataDTO.setScene(printData.getScene());
                return dataDTO;
            }).collect(Collectors.toList());
            requestDTO.setPrintData(printDataDTOS);
            List<OutputConfigDTO> outputConfigDTOS = new ArrayList<>();
            OutputConfigDTO outputConfigDTO = new OutputConfigDTO();
            outputConfigDTO.setOutputType(1);
            outputConfigDTO.setDataFormat(1);
            outputConfigDTO.setFileFormat(1);
            outputConfigDTOS.add(outputConfigDTO);
            requestDTO.setOutputConfig(outputConfigDTOS);
            request.setQueryRenderDTO(requestDTO);
            request.setUseJosAuth(false);

            // 设置插件，必须的操作，不同类型的应用入参不同，请看入参注释，公共参数按顺序分别为AppKey、AppSecret、AccessToken
            // 使用开放平台ISV/自研商家应用调用接口
            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(credential1.getAppKey(), credential1.getSecretKey(), credential1.getAccessToken());
            request.addLopPlugin(lopPlugin);

            CloudPrintRenderLopResponse response = client.execute(request);
            PrintResultDTO resultDTO = response.getPrintResultDTO();
            log.info(JSON.toJSONString(resultDTO));
            List<String> urls = resultDTO.getResult().stream().map(RenderResultDTO::getUrl).toList();
            logisticsPrint.setUrls(urls);
            return urls;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 物流轨迹订阅
     * @param crmOrder
     * @return
     */
    @Override
    public Object traceSubscribe(CrmOrder crmOrder) {
        if (ObjUtil.isNotEmpty(crmOrder.getLogisticsPlatformCode()) && ObjUtil.isNotEmpty(crmOrder.getLogisticsNo()) && Objects.equals(crmOrder.getShippingType(), ShippingType.SELF_SHIPPING.getType())) {
            switch (ExpressCompanyEnum.getByCode(crmOrder.getLogisticsPlatformCode())) {
                case JD,JINGDONGKUAIYUN -> {
                    TraceSubscribeBo traceSubscribeBo = new TraceSubscribeBo();
                    traceSubscribeBo.setMobile(StrUtil.subSufByLength(crmOrder.getReceiverPhone(), 4));
                    traceSubscribeBo.setWaybillCode(crmOrder.getLogisticsNo());
                    return this.traceSubscribe(traceSubscribeBo);
                }
            }
        }
        return null;
    }

    /**
     * 物流轨迹订阅
     * @param traceSubscribe
     */
    @Override
    public Object traceSubscribe(TraceSubscribeBo traceSubscribe) {
        log.info("开始订阅物流轨迹");
        Credential credential1 = openApiCredentialProperties.getJdLogistics().get(0);
        // 入参对象（请记得更换为自己要使用的接口入参对象）
        EcapV1OrdersTraceSubscribeLopRequest request = new EcapV1OrdersTraceSubscribeLopRequest();
        CommonSubscribeTraceRequest commonSubscribeTraceRequest = new CommonSubscribeTraceRequest();
        commonSubscribeTraceRequest.setMobile(traceSubscribe.getMobile());
        commonSubscribeTraceRequest.setOrderOrigin(1);
        commonSubscribeTraceRequest.setCustomerCode(credential1.getCustomerCode());
        commonSubscribeTraceRequest.setBusinessUnitCode(commonSubscribeTraceRequest.getCustomerCode());

        request.setRequest(commonSubscribeTraceRequest);
        request.setUseJosAuth(false);
        LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(credential1.getAppKey(), credential1.getSecretKey(), credential1.getAccessToken());
        request.addLopPlugin(lopPlugin);
        try {
            EcapV1OrdersTraceSubscribeLopResponse response = client.execute(request);
            CommonSubscribeResponse result = response.getResult();
            log.info(JSON.toJSONString(result));
            if (result.getCode() == 0) {
                log.info("订阅成功");
            } else {
                log.error("订阅失败");
            }
            return result;
        } catch (LopException e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public Integer interceptSub(String interceptData) {
        /*
        {
            "waybillCode":"JDV789789789",
            "newWaybillCode":"JDV785412300",
            "interceptState":1, // 拦截状态，0-拦截成功、1-退回成功、2-拦截失败、3-退回失败
            "interceptStateDesc":"拦截成功",
            "siteName":"xxx分拣中心/xxx站点",
            "operateTime":"2024-09-03 21:16:06"
        }
         */
        JSONObject parse = JSONObject.parse(interceptData);
        String waybillCode = parse.getString("waybillCode");
        String siteName = parse.getString("siteName");
        Integer interceptState = parse.getInteger("interceptState");

        CrmLogisticsRecord crmLogisticsRecord = crmLogisticsRecordService.getOne(Wrappers.<CrmLogisticsRecord>lambdaQuery().eq(CrmLogisticsRecord::getLogisticsNo, waybillCode));

        if(Arrays.asList(0, 1).contains(interceptState)){
            CrmLogisticsRecord updateLogisticsRecord = new CrmLogisticsRecord();
            updateLogisticsRecord.setId(crmLogisticsRecord.getId());
            updateLogisticsRecord.setLogisticsStatus( "6");
            crmLogisticsRecordService.updateById(updateLogisticsRecord);

            CrmOrder updateOrder = new CrmOrder();
            updateOrder.setOrderId(crmLogisticsRecord.getOrderId());
            updateOrder.setLogisticsStatus(updateLogisticsRecord.getLogisticsStatus());
            updateOrder.setLogisticsProgress(siteName);
            updateOrder.setOrderStatus(CrmOrderStatus.CANCELED.getCode());
            crmOrderMapper.updateById(updateOrder);

            return 1;
        }

        return 0;
    }

    /**
     * 京东物流轨迹信息订阅
     * state	operationTitle	category	categoryName	说明	operationRemark
     * 200018	揽收任务分配司机		揽收
     * 200034	揽收任务分配		揽收	下单后4秒-10秒左右就会触发，包含快递员手机号
     * 200035	配送员接受揽收任务		揽收
     * 200001	揽收		揽收
     * 200020	换单打印		打印	拒收后的新运单号在此节点生成；新运单号可从operationRemark获取（需要截取）	换单打印，新运单号JDAZ03069938052
     * 200010	取消完成		取消
     * 200052	终止揽收		揽收
     * 200053	揽件再取		揽收
     * 200054	上门接货退货完成		揽收
     * 200075	站点收货		运输
     * 200076	封车		运输
     * 200077	站点装箱		运输
     * 200017	分拣中心收货		运输
     * 10032	分拣验收		运输
     * 200072	分拣中心分拣		运输
     * 10054	分拣中心发货		运输
     * 11000	派件		派送
     * 200023	协商再投		派送
     * 200003	站点再投		派送
     * 10034	妥投		完成
     * 10035	拒收		完成
     * @param traceMsg
     * @return
     */
    @Override
    public Integer jdTraceMsgSub(String traceMsg) {
        /*
        {
            "routeProvinceName":"北京",
            "operateSiteId":"1595504",
            "orderId":"YD2022090808354",
            "operationTitle":"揽收",
            "routeDistrictName":"四环到五环之间",
            "categoryName":"已揽收",
            "operationTime":"2022-09-09 01:44:17",
            "routeAddress":"北京市丰台区新发地批发市场三农门东排21号",
            "routeCityName":"丰台区",
            "waybillCode":"JDVA15953261325",
            "state":"200001",
            "scanType":"-190",
            "category":420,
            "operateSite":"北京顺发专揽营业部",
            "operationRemark":"您的快件已由【北京顺发专揽营业部】揽收完成"
        }
         */
        JSONObject parse = JSONObject.parse(traceMsg);
        CrmLogisticsTrack crmLogisticsTrack = JSON.parseObject(traceMsg, CrmLogisticsTrack.class);
        crmLogisticsTrack.setCustomerOrderNo(parse.getString("orderId"));
        crmLogisticsTrack.setWaybillNo(parse.getString("waybillCode"));
        crmLogisticsTrack.setExtendInfo(traceMsg);
        crmLogisticsTrack.setLogisticsNo(ExpressCompanyEnum.JINGDONGKUAIYUN.getCode());
        crmLogisticsTrack.setLogisticsName(ExpressCompanyEnum.JINGDONGKUAIYUN.getName());
        crmLogisticsTrackMapper.insert(crmLogisticsTrack);


        CrmLogisticsRecord crmLogisticsRecord = crmLogisticsRecordService.getOne(Wrappers.<CrmLogisticsRecord>lambdaQuery().eq(CrmLogisticsRecord::getLogisticsNo, crmLogisticsTrack.getWaybillNo()));

        CrmOrder crmOrder = crmOrderMapper.selectOne(Wrappers.<CrmOrder>lambdaQuery().eq(CrmOrder::getOrderNo, crmLogisticsTrack.getCustomerOrderNo()));

        CrmOrder updateOrder = new CrmOrder();
        updateOrder.setOrderId(crmOrder.getOrderId());
        updateOrder.setLogisticsProgress(crmLogisticsTrack.getOperationRemark());
        if ("10034".equals(crmLogisticsTrack.getState())){
            if (ObjUtil.isNotEmpty(crmOrder)){
                if (!crmOrder.getLogisticsStatus().equals(LogisticsStatus.SIGNED.getCode()) && crmOrder.getOrderType().equals(OrderType.REPURCHASE.getType())) {
                    SysNotice sysNotice = SysNotice.builder()
                            .noticeTitle("订单签收成功")
                            .noticeType("1")
                            .noticeContent("订单：" + crmOrder.getOrderNo() + "已签收,请注意跟进！")
                            .sendId(0L)
                            .userId(crmOrder.getSalesmanId())
                            .msgType(MsgType.RECEIPTED.getValue()).build();
                    SpringUtil.publishEvent(sysNotice);
                }
            }
            updateOrder.setLogisticsSignTime(DateUtil.date());
            updateOrder.setLogisticsStatus("1");
            updateOrder.setOrderStatus(CrmOrderStatus.SIGNED.getCode());
            crmLogisticsRecord.setLogisticsStatus(updateOrder.getLogisticsStatus());
        }
        if ("10035".equals(crmLogisticsTrack.getState())){
            if (ObjUtil.isNotEmpty(crmOrder)){
                if (!crmOrder.getLogisticsStatus().equals(LogisticsStatus.SIGNED.getCode()) && crmOrder.getOrderType().equals(OrderType.REPURCHASE.getType())) {
                    SysNotice sysNotice = SysNotice.builder()
                            .noticeTitle("订单拒签")
                            .noticeType("1")
                            .noticeContent("订单：" + crmOrder.getOrderNo() + "已拒签,请注意跟进！")
                            .sendId(0L)
                            .userId(crmOrder.getSalesmanId())
                            .msgType(MsgType.RECEIPTED.getValue()).build();
                    SpringUtil.publishEvent(sysNotice);
                }
            }
            updateOrder.setLogisticsSignTime(DateUtil.date());
            updateOrder.setLogisticsStatus("2");
            updateOrder.setOrderStatus(CrmOrderStatus.SIGNED.getCode());
            crmLogisticsRecord.setLogisticsStatus(updateOrder.getLogisticsStatus());
        }
        updateOrder.setLogisticsProgress(crmLogisticsTrack.getOperationRemark());
        crmLogisticsRecordService.updateById(crmLogisticsRecord);
        return crmOrderMapper.updateById(updateOrder);
    }

}
